package com.hup.utils.swing.customView.colorChooser;

import lombok.Setter;
import lombok.extern.log4j.Log4j2;

import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.MemoryImageSource;

/**
 * 绘制[调色控件]的基础类
 * @author hugan
 * @date 2020/4/10
 */
@Log4j2
public abstract class AbsColorLabel extends JLabel implements IColorComponent {

    /**
     * 指示当前颜色的游标颜色:两种颜色配合(反色),可以解决所有颜色下游标可见性问题
     */
    protected static final Color CURSOR_COLOR_C1 = new Color(255, 128, 0);
    protected static final Color CURSOR_COLOR_C2 = new Color(0, 127, 255);

    protected int width;
    protected int height;
    @Setter
    protected ColorInvoker colorInvoker;

    /**
     * 当前颜色
     */
    protected Color color = new Color(80, 217, 255);
    /**
     * 用于构造图像数据,使用{@link MemoryImageSource}将一元数组转成Image
     */
    protected int[] pix;
    protected Image image;

    public AbsColorLabel() {
        setFocusable(true);
        pix = initPix();
        updateTo(color);

        MouseAdapter mouseAdapter = new MouseAdapter() {
            @Override
            public void mouseDragged(MouseEvent e) {
                handleMouseAction(e, false);
            }

            @Override
            public void mousePressed(MouseEvent e) {
                handleMouseAction(e, true);
            }
        };
        addMouseListener(mouseAdapter);
        addMouseMotionListener(mouseAdapter);
    }

    private void handleMouseAction(MouseEvent e, boolean isPress) {
        if (!SwingUtilities.isLeftMouseButton(e)) return;
        requestFocus();
        Color color = getMouseColor(isPress, e.getX(), e.getY());
        if (color != null) {
            updateTo(color);
            if (colorInvoker != null) colorInvoker.fireColorChanged(AbsColorLabel.this, color);
        }
    }

    @Override
    public void setBounds(int x, int y, int width, int height) {
        super.setBounds(x, y, width, height);
        this.width = width;
        this.height = height;
    }

    @Override
    public void updateTo(Color color) {
        boolean needUpdateImage = needUpdateImage(color, this.color);
        this.color = color;
        if (needUpdateImage) {
            if (image != null) image.flush();
            image = updateImageByColor();
        }
        repaint();
    }

    @Override
    public final void paint(Graphics g) {
        super.paint(g);
        //外边框:起始像素是0,结束像素是[长度-1]
        boolean drew = doPaintGraphics(g);
        if (!drew) {
            g.setColor(Color.BLACK);
            g.drawRect(0, 0, width - 1, height - 1);
        }
    }

    /**
     * 初始化颜色数组
     */
    protected abstract int[] initPix();

    /**
     * @return 颜色更新后是否需要重绘image;默认需要
     */
    protected boolean needUpdateImage(Color newer, Color older) {
        return true;
    }

    /**
     * @return notNull,颜色更新后, 构造新的图像(与当前view的尺寸无关系的图像)
     */
    protected abstract Image updateImageByColor();

    /**
     * {@link #paint(Graphics)}时绘制图像的方法
     *
     * @return 是否已绘制:false-实现类没绘制图像,父类绘制默认的黑边框;true-实现类已经绘制了自己的图像
     */
    protected boolean doPaintGraphics(Graphics g) {
        return false;
    }

    /**
     * @param isPress 按下还是拖拽
     * @return 鼠标按下或拖拽时坐标的颜色;null-无鼠标功能,或不修改颜色时返回null
     */
    protected Color getMouseColor(boolean isPress, int x, int y) {
        return null;
    }

    /**
     * @param mX 鼠标点击或拖拽的x坐标
     * @return x坐标所在的pix的index
     * @apiNote 仅pix是一维数据时使用
     */
    protected int getMxIndex(int mX) {
        int curI = (int) (mX / (getWidth() / (pix.length + 0d)));
        if (curI < 0) {
            curI = 0;
        } else if (curI >= pix.length) {
            curI = pix.length - 1;
        }
        return curI;
    }

    /**
     * @return [0,255]
     */
    protected int getBrightness(Color color) {
        return Math.max(color.getRed(), Math.max(color.getGreen(), color.getBlue()));
    }

}
